#!/usr/bin/env python

from collections import defaultdict
import struct
import sys
import time

import numpy
import tables

OKAY = 0x6F6B6179
WHA  = 0x7768613f
RITE = 0x72697465 
READ = 0x72656164 
PING = 0x70696e67
EVNT = 0x65766e74
WAVE = 0x77617665

badpkt_bits = {0x1: "Packet size over expected maximum",
               0x2: "Packet type not understood",
               0x4: "Mismatched command destination (SCROD id/rev or I2C)",
               0x8: "Command type not understood",
               0x10: "Bad command checksum",
               0x20: "Bad packet checksum",
               }

def parse_adcs(words):
    adcs = []
    mlo = 0xFFFF
    mhi = 0xFFFF0000
    for w in words:
        adcs.append(w & mlo)
        adcs.append((w & mhi) >> 16)

    return adcs

def asic_info(word):
    win = word & 0x1FF
    ch = (word & 0xe00) >> 9
    row = (word & 0x3000) >> 12
    col = (word & 0xc000) >> 14
    
    return row, col, ch, win


def main():
    adc_counts = []
    windows    = []
    samples    = []

    pedestals   = numpy.zeros((512,64), dtype=numpy.float32)
    ntrigs_recv = numpy.zeros((512,64))

    bad_packets = []

    with open(sys.argv[1]) as fpin:
        bytestr = fpin.read()

    if len(bytestr) % 4 != 0:
        msg = "Data length ({0} bytes) not a multiple of 4"
        raise ValueError(msg.format(len(bytestr)))

    nwords_file = len(bytestr) / 4
    words = numpy.asarray(struct.unpack(str(nwords_file) + "I", 
                                        bytestr))
    
    packet_indices = numpy.where(words == 0xbe11e2)[0]
    ctr = defaultdict(lambda: 0)
    wins = []
    for j in xrange(len(packet_indices) - 1):
        start = packet_indices[j]
        stop  = packet_indices[j+1]

        packet = words[start:stop]

        ctr[hex(packet[2])] += 1

        if packet[2] == WHA:
            bad_packets.append(packet)
            continue
        
        if packet[2] != WAVE:
            continue

        row, col, ch, win = asic_info(packet[7])
        
        adcs = parse_adcs(packet[9:-1])

        for i, adc in enumerate(adcs):
            adc_counts.append(adc)
            windows.append(win)
            samples.append(i)
            
            try:
                pedestals[win][i] += adc
                ntrigs_recv[win][i] += 1
            except IndexError:
                print "IndexError:", win, i
                raise


    print "output arrs:", len(adc_counts), len(windows), len(samples)

    output_arr = numpy.array(zip(windows, samples, adc_counts))
    
    fpout = tables.openFile(sys.argv[1].rsplit('.', 1)[0] + '.h5', 'w')
    fpout.createArray(fpout.root, 'data', output_arr)
    fpout.close()
    
    pedestals /= ntrigs_recv
    numpy.savetxt(sys.argv[1].rsplit('.', 1)[0] + '.peds.txt', 
                  pedestals)
            
    keys = sorted(ctr.keys())
    for k in keys:
        print k, ctr[k]

    if len(bad_packets) > 0:
        with open("wha-packets.txt", 'w') as fp:
            badpkt_ctr = defaultdict(lambda: 0)
            for pkt in bad_packets:
                if pkt[5] in badpkt_bits:
                    badpkt_ctr[pkt[5]] += 1
                
                fp.write('\n'.join(map(hex, pkt)))
                fp.write('\n\n')

        print len(bad_packets), "bad packets encountered;",
        print " data left in `wha-packets.txt'; summary follows:"
            
        keys = sorted(badpkt_ctr.keys())
        for k in keys:
            print badpkt_bits[k], badpkt_ctr[k]     

    

if __name__ == "__main__":
    sys.exit(main())
